home *** CD-ROM | disk | FTP | other *** search
- #ifdef sccsid
- static char sccsid[] = "@(#)iu_simulator.c 1.6 88/03/03 SMI";
- #endif
-
- /*
- * Copyright (c) 1988 by Sun Microsystems, Inc.
- */
-
- /* Integer Unit simulator for Sparc FPU simulator. */
-
- /*
- * This whole file refuses to lint.
- */
- #ifndef lint
- #include <sun4/fpu/fpu_simulator.h>
- #include <sun4/fpu/globals.h>
-
- #define FPU_REG_FIELD unsigned_reg /* Coordinate with FPU_REGS_TYPE. */
- #define FPU_FSR_FIELD unsigned_reg /* Coordinate with FPU_FSR_TYPE. */
-
- PRIVATE enum ftt_type
- fbcc(pinst, pregs, pfpu)
- fp_inst_type pinst; /* FPU instruction to simulate. */
- struct regs *pregs; /* Pointer to PCB image of registers. */
- struct fpu *pfpu; /* Pointer to FPU register block. */
-
- {
- union {
- fsr_type fsr;
- long i;
- } klugefsr;
- union {
- fp_inst_type fi;
- int i;
- } kluge;
- enum fcc_type fcc;
- enum icc_type {
- fbn, fbne, fblg, fbul, fbl, fbug, fbg, fbu,
- fba, fbe, fbue, fbge, fbuge, fble, fbule, fbo
- } icc;
-
- unsigned annul, takeit;
-
- klugefsr.i = pfpu->fpu_fsr;
- fcc = klugefsr.fsr.fcc;
- icc = (enum icc_type) (pinst.rd & 0xf);
- annul = pinst.rd & 0x10;
-
- switch (icc) {
- case fbn:
- takeit = 0;
- break;
- case fbl:
- takeit = fcc == fcc_less;
- break;
- case fbg:
- takeit = fcc == fcc_greater;
- break;
- case fbu:
- takeit = fcc == fcc_unordered;
- break;
- case fbe:
- takeit = fcc == fcc_equal;
- break;
- case fblg:
- takeit = (fcc == fcc_less) || (fcc == fcc_greater);
- break;
- case fbul:
- takeit = (fcc == fcc_unordered) || (fcc == fcc_less);
- break;
- case fbug:
- takeit = (fcc == fcc_unordered) || (fcc == fcc_greater);
- break;
- case fbue:
- takeit = (fcc == fcc_unordered) || (fcc == fcc_equal);
- break;
- case fbge:
- takeit = (fcc == fcc_greater) || (fcc == fcc_equal);
- break;
- case fble:
- takeit = (fcc == fcc_less) || (fcc == fcc_equal);
- break;
- case fbne:
- takeit = fcc != fcc_equal;
- break;
- case fbuge:
- takeit = fcc != fcc_less;
- break;
- case fbule:
- takeit = fcc != fcc_greater;
- break;
- case fbo:
- takeit = fcc != fcc_unordered;
- break;
- case fba:
- takeit = 1;
- break;
- }
- if (takeit) { /* Branch taken. */
- int tpc;
-
- kluge.fi = pinst;
- tpc = pregs->r_pc;
- if (annul && (icc == fba)) { /* fba,a is wierd */
- pregs->r_pc = tpc + (int) ((kluge.i << 10) >> 8);
- pregs->r_npc = pregs->r_pc + 4;
- } else {
- pregs->r_pc = pregs->r_npc;
- pregs->r_npc = tpc + (int) ((kluge.i << 10) >> 8);
- }
- } else { /* Branch not taken. */
- if (annul) { /* Annul next instruction. */
- pregs->r_pc = pregs->r_npc + 4;
- pregs->r_npc += 8;
- } else { /* Execute next instruction. */
- pregs->r_pc = pregs->r_npc;
- pregs->r_npc += 4;
- }
- }
- return (ftt_none);
- }
-
- PRIVATE enum ftt_type
- fldst(pinst, pregs, pwindow, pfpu)
- fp_inst_type pinst; /* FPU instruction to simulate. */
- struct regs *pregs; /* Pointer to PCB image of registers. */
- struct rwindow *pwindow;/* Pointer to locals and ins. */
- struct fpu *pfpu; /* Pointer to FPU register block. */
-
- /* Simulator for loads and stores between floating-point unit and memory. */
-
- {
- unsigned nrs1, nrs2, nrd; /* Register number fields. */
- freg_type f;
- int ea;
- int i;
- union {
- fp_inst_type fi;
- int i;
- } kluge;
- enum ftt_type ftt;
-
- nrs1 = pinst.rs1;
- nrs2 = pinst.rs2;
- nrd = pinst.rd;
- if (pinst.ibit == 0) { /* effective address = rs1 + rs2 */
- ftt = read_iureg(nrs1, pregs, pwindow, &ea);
- if (ftt != ftt_none)
- return (ftt);
- ftt = read_iureg(nrs2, pregs, pwindow, &i);
- if (ftt != ftt_none)
- return (ftt);
- ea += i;
- } else { /* effective address = rs1 + imm13 */
- kluge.fi = pinst;
- ea = (kluge.i << 19) >> 19; /* Extract simm13 field. */
- ftt = read_iureg(nrs1, pregs, pwindow, &i);
- if (ftt != ftt_none)
- return (ftt);
- ea += i;
- }
-
- fptrapaddr = (char *) ea; /* setup bad addr in case we trap */
- switch (pinst.op3 & 7) {
- case 0: /* LDF */
- ftt = _fp_read_word((caddr_t) ea, &(f.int_reg));
- if (ftt != ftt_none)
- return (ftt);
- pfpu->fpu_regs[nrd] = f.FPU_REG_FIELD;
- break;
- case 1: /* LDFSR */
- ftt = _fp_read_word((caddr_t) ea, &(f.int_reg));
- if (ftt != ftt_none)
- return (ftt);
- pfpu->fpu_fsr = f.FPU_FSR_FIELD;
- break;
- case 3: /* LDDF */
- if ((ea & 0x7) != 0)
- return (ftt_alignment); /* Require double-alignment. */
- ftt = _fp_read_word((caddr_t) ea, &(f.int_reg));
- if (ftt != ftt_none)
- return (ftt);
- pfpu->fpu_regs[DOUBLE_E(nrd)] = f.FPU_REG_FIELD;
- ftt = _fp_read_word((caddr_t) (ea + 4), &(f.int_reg));
- if (ftt != ftt_none)
- return (ftt);
- pfpu->fpu_regs[DOUBLE_F(nrd)] = f.FPU_REG_FIELD;
- break;
- case 4: /* STF */
- f.FPU_REG_FIELD = pfpu->fpu_regs[nrd];
- ftt = _fp_write_word((caddr_t) ea, f.int_reg);
- if (ftt != ftt_none)
- return (ftt);
- break;
- case 5: /* STFSR */
- f.FPU_FSR_FIELD = pfpu->fpu_fsr;
- f.FPU_FSR_FIELD &= ~0x301000; /* Clear reserved bits. */
- f.FPU_FSR_FIELD |= 0x0E0000; /* Set version number=7 . */
- ftt = _fp_write_word((caddr_t) ea, f.int_reg);
- if (ftt != ftt_none)
- return (ftt);
- break;
- case 7: /* STDF */
- if ((ea & 0x7) != 0)
- return (ftt_alignment); /* Require double-alignment. */
- f.FPU_REG_FIELD = pfpu->fpu_regs[DOUBLE_E(nrd)];
- ftt = _fp_write_word((caddr_t) ea, f.int_reg);
- if (ftt != ftt_none)
- return (ftt);
- f.FPU_REG_FIELD = pfpu->fpu_regs[DOUBLE_F(nrd)];
- ftt = _fp_write_word((caddr_t) (ea + 4), f.int_reg);
- if (ftt != ftt_none)
- return (ftt);
- break;
- default:
- fptrapaddr = (char *) pregs->r_pc; /* addr of unimp inst */
- return (ftt_unimplemented);
- }
-
- pregs->r_pc = pregs->r_npc; /* Do not retry emulated instruction. */
- pregs->r_npc += 4;
- return (ftt_none);
- }
-
- /* PUBLIC FUNCTIONS */
-
- enum ftt_type
- _fp_iu_simulator(pinst, pregs, pwindow, pfpu)
- fp_inst_type pinst; /* FPU instruction to simulate. */
- struct regs *pregs; /* Pointer to PCB image of registers. */
- struct rwindow *pwindow;/* Pointer to locals and ins. */
- struct fpu *pfpu; /* Pointer to FPU register block. */
-
- {
- switch (pinst.hibits) {
- case 0:
- return fbcc(pinst, pregs, pfpu);
- case 3:
- return fldst(pinst, pregs, pwindow, pfpu);
- default:
- return ftt_unimplemented;
- }
- }
- #endif /* lint */
-